package com.warm.common.doc;

import com.alibaba.fastjson.JSONObject;
import com.warm.common.util.QRCodeUtil;
import com.warm.common.word.Word;
import freemarker.template.Configuration;
import freemarker.template.Template;
import lombok.Data;
import lombok.Getter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.util.CollectionUtils;
import org.springframework.util.FileCopyUtils;

import java.io.*;
import java.net.HttpURLConnection;
import java.net.MalformedURLException;
import java.net.URL;
import java.util.ArrayList;
import java.util.Base64;
import java.util.Enumeration;
import java.util.List;
import java.util.zip.ZipEntry;
import java.util.zip.ZipFile;
import java.util.zip.ZipOutputStream;

@Slf4j
public class DocUtil {

    private static Configuration cfg;
    private static Doc doc;

    private static String TEMP_DIR = "./temp/";
    private static String separator = "/";

    public static void init(String templateDir){ // 模板文件夹路径
        try {
            // 创建 freemarker 实例
            cfg = new Configuration(Configuration.VERSION_2_3_0);
            cfg.setDefaultEncoding("utf-8");
            cfg.setDirectoryForTemplateLoading(new File(templateDir));
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static ByteArrayInputStream renderTemplate(Doc data, String templateName) {
        ByteArrayInputStream in = null;
        try {
            Template template = cfg.getTemplate(templateName);
            StringWriter writer = new StringWriter();
            template.process(data, writer);
            in = new ByteArrayInputStream(writer.toString().getBytes("utf-8"));
        } catch (Exception e) {
            log.error("模板生成错误！",e);
        }
        return in;
    }

    public static void export(Doc doc1){
        doc = doc1;
        init(doc.getTemplateDir());

        new File(TEMP_DIR).mkdirs();
        String outFile = TEMP_DIR + System.currentTimeMillis() + doc.getType().getType();

        ZipOutputStream zipout = null;
        OutputStream os = null;
        try {
            os = new FileOutputStream(outFile);
            zipout = new ZipOutputStream(os);
            File sourceFile = new File(doc.getConfig().getSourceFilePath());

            ZipFile zipFile = new ZipFile(sourceFile);
            if(doc.getType().equals(Doc.TypeEnum.WORD)){
                writeImage(zipout);
                coverWord(zipFile, zipout);
            } else {
                coverExcel(zipFile, zipout);
            }
        } catch (Exception e) {
            log.error("word导出失败:",e);
        }finally {
            closeZipStream(zipout);
            closeOutStream(os);
        }
    }

    private static void writeImage(ZipOutputStream zipout) throws IOException {
        int len = -1;
        byte[] buffer = new byte[1024];
        List<Doc.Image> imageList = doc.getImageList();
        if (!CollectionUtils.isEmpty(imageList)){
            ZipEntry next = null;
            for (Doc.Image image : imageList){
                next = new ZipEntry("word" + separator + "media" + separator + image.getFilename());
                zipout.putNextEntry(new ZipEntry(next.toString()));
                InputStream in = null;
                if(Doc.ImageEnum.FILE.getType().equals(image.getType())){
                    in = file2InputStream((String) image.getData());
                } else if(Doc.ImageEnum.URL.getType().equals(image.getType())){
                    in = url2InputStream((String) image.getData());
                } else if(Doc.ImageEnum.STREAM.getType().equals(image.getType())){
                    in = (InputStream) image.getData();
                } else if(Doc.ImageEnum.BASE64.getType().equals(image.getType())){
                    in = new ByteArrayInputStream(Base64.getDecoder().decode((String) image.getData()));
                } else if(Doc.ImageEnum.QRCODE.getType().equals(image.getType())){
                    in = QRCodeUtil.encode((String) image.getData(), null);;
                }
                while ((len = in.read(buffer)) != -1) {
                    zipout.write(buffer, 0, len);
                }
                in.close();
            }
        }
    }

    private static void coverWord(ZipFile zipFile, ZipOutputStream zipout){
        try {
            Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();

            int len = -1;
            byte[] buffer = new byte[1024];
            //开始覆盖文档
            while (zipEntrys.hasMoreElements()) {
                ZipEntry next = zipEntrys.nextElement();
                if(next.toString().indexOf("media") > 0){//包含 media 的都跳出
                    continue;
                }
                zipout.putNextEntry(new ZipEntry(next.getName()));
                if("word/_rels/document.xml.rels".equals(next.getName()) && doc.getConfig().getTemplateFileNames().contains("document.xml.rels")){
                    ByteArrayInputStream inStream = renderTemplate(doc, "document.xml.rels");
                    while ((len = inStream.read(buffer)) != -1) {
                        zipout.write(buffer, 0, len);
                    }
                    inStream.close();
                } else if("word/document.xml".equals(next.getName()) && doc.getConfig().getTemplateFileNames().contains("document.xml")){
                    ByteArrayInputStream inStream = renderTemplate(doc, "document.xml");
                    while ((len = inStream.read(buffer)) != -1) {
                        zipout.write(buffer, 0, len);
                    }
                    inStream.close();
                } else { // 其他文件
                    InputStream is = zipFile.getInputStream(next);
                    while ((len = is.read(buffer)) != -1) {
                        zipout.write(buffer, 0, len);
                    }
                    is.close();
                }
            }
        } catch (IOException e){
            log.error("cover file error...");
        }
    }

    private static void coverExcel(ZipFile zipFile, ZipOutputStream zipout){
        try {
            Enumeration<? extends ZipEntry> zipEntrys = zipFile.entries();

            int len = -1;
            byte[] buffer = new byte[1024];
            //开始覆盖文档
            while (zipEntrys.hasMoreElements()) {
                ZipEntry next = zipEntrys.nextElement();
                zipout.putNextEntry(new ZipEntry(next.getName()));
                if("xl/worksheets/sheet1.xml".equals(next.getName()) && doc.getConfig().getTemplateFileNames().contains("sheet1.xml")){
                    ByteArrayInputStream inStream = renderTemplate(doc, "sheet1.xml");
                    while ((len = inStream.read(buffer)) != -1) {
                        zipout.write(buffer, 0, len);
                    }
                    inStream.close();
                } else if("xl/worksheets/sheet2.xml".equals(next.getName()) && doc.getConfig().getTemplateFileNames().contains("sheet2.xml")){
                    ByteArrayInputStream inStream = renderTemplate(doc, "sheet2.xml");
                    while ((len = inStream.read(buffer)) != -1) {
                        zipout.write(buffer, 0, len);
                    }
                    inStream.close();
                }else if("xl/worksheets/sheet3.xml".equals(next.getName()) && doc.getConfig().getTemplateFileNames().contains("sheet3.xml")){
                    ByteArrayInputStream inStream = renderTemplate(doc, "sheet3.xml");
                    while ((len = inStream.read(buffer)) != -1) {
                        zipout.write(buffer, 0, len);
                    }
                    inStream.close();
                } else { // 其他文件
                    InputStream is = zipFile.getInputStream(next);
                    while ((len = is.read(buffer)) != -1) {
                        zipout.write(buffer, 0, len);
                    }
                    is.close();
                }
            }
        } catch (IOException e){
            log.error("cover file error...");
        }
    }


    public static InputStream file2InputStream(String filepath){
        InputStream in = null;
        try {
            File file = new File(filepath);
            if(file.exists()){
                in = new FileInputStream(file);
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
        return in;
    }

    public static InputStream url2InputStream(String fileUrl){
        InputStream in = null;
        try {
            URL url = new URL(fileUrl);
            in = url.openStream();
        } catch (MalformedURLException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }
        return in;
    }

    public static String url2Base64Str(String fileUrl){
        HttpURLConnection conn = null;
        InputStream inputStream = null;
        try {
            conn = (HttpURLConnection) new URL(fileUrl).openConnection();
            conn.setRequestMethod("GET");
            conn.setConnectTimeout(5000);
            inputStream = conn.getInputStream();
            return Base64.getEncoder().encodeToString(FileCopyUtils.copyToByteArray(inputStream));
        } catch (Exception e) {
            System.out.println(e.getMessage());
        } finally {
            closeInStream(inputStream);
            if(conn != null) {
                conn.disconnect();
            }
        }
        return null;
    }

    private static void closeZipStream(ZipOutputStream zipout){
        if(zipout == null) return;
        try {
            zipout.close();
        } catch (IOException e) {
            log.error("io异常");
        }
    }

    private static void closeOutStream(OutputStream os){
        if(os == null) return;
        try {
            os.close();
        } catch (IOException e) {
            log.error("io异常");
        }
    }

    private static void closeInStream(InputStream in){
        if(in == null) return;
        try {
            in.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}
